#pragma once

#include <fstream>
#include <sstream>
#include <vector>
#include <string>

#include "Object.h"

#include "DualSword.h"
#include "Longsword.h"
#include "SwordAndShield.h"
#include "Inventory.h"

using namespace std;

#define DEBUG

// Check Whether Debug Mode
#ifdef DEBUG
	#define PRINTLOAD true
	#define PRINTSAVE true
#else
	#define PRINTLOAD false
	#define PRINTSAVE false
#endif

// CHARACTER DATA
#define CHAR_POS_X							0
#define CHAR_POS_Y							500

#define CHAR_POS_X_HUD						400
#define CHAR_POS_Y_HUD						400

#define CHAR_SIZE_X							45
#define CHAR_SIZE_Y							60

#define CHAR_LIVES							3

#define CHAR_SPEED_MOVE						200.0f
#define CHAR_SPEED_JUMP						( GRAVITY * 3 / 2 )

#define CHAR_LIMIT_JUMP						170.0f

// TIMER DATA
#define	TIMER_SPRITE_CHAR_IDLE				100
#define	TIMER_SPRITE_CHAR_INAIR				100
#define	TIMER_SPRITE_CHAR_DEATH				1000
#define	TIMER_SPRITE_CHAR_HURT				200
#define	TIMER_SPRITE_CHAR_MOVE				100
#define	TIMER_SPRITE_CHAR_PRIMARY			100
#define	TIMER_SPRITE_CHAR_SECONDARY			100

#define TIMER_CHAR_STATUS_INVUL_AFTER_HIT	1000

// WEAPON DATA
#define WEAPON_DUELSWORD_MOVEBACK_X_LIMIT	100.0f
#define	WEAPON_DUELSWORD_MOVEBACK_X_SPEED	( 50.0f + CHAR_SPEED_MOVE )
#define	WEAPON_DUELSWORD_CHARGE_TIME		800

#define	WEAPON_SWORDANDSHIELD_TIME_ALLOWED	3000
#define WEAPON_SWORDANDSHIELD_CHARGE_TIME	3000

#define WEAPONDEFAULT						CWeapon::DUALSWORD

// SAVE DATA
#define FILEPATH_SAVELOAD	"character.dat"

//--------------------------------------------------------------------
// FILEPATH CHARACTER NORMAL
//--------------------------------------------------------------------

//--------------------------------------------------------------------
#define FILEPATH_CHARIMAGE_IDLE_START	"images/Character/Character/IDLE_1.tga"
#define FILEPATH_CHARIMAGE_IDLE_END		"images/Character/Character/IDLE_1.tga"
//--------------------------------------------------------------------
#define FILEPATH_CHARIMAGE_INAIR_START	"images/Character/Character/INAIR_1.tga"
#define FILEPATH_CHARIMAGE_INAIR_END	"images/Character/Character/INAIR_1.tga"
//--------------------------------------------------------------------
#define FILEPATH_CHARIMAGE_DEATH_START	"images/Character/Character/DEATH_1.tga"
#define FILEPATH_CHARIMAGE_DEATH_END	"images/Character/Character/DEATH_1.tga"
//--------------------------------------------------------------------
#define FILEPATH_CHARIMAGE_HURT_START	"images/Character/Character/HURT_1.tga"
#define FILEPATH_CHARIMAGE_HURT_END		"images/Character/Character/HURT_2.tga"
//--------------------------------------------------------------------
#define FILEPATH_CHARIMAGE_MOVE_START	"images/Character/Character/MOVE_1.tga"
#define FILEPATH_CHARIMAGE_MOVE_1		"images/Character/Character/MOVE_2.tga"
#define FILEPATH_CHARIMAGE_MOVE_2		"images/Character/Character/MOVE_3.tga"
#define FILEPATH_CHARIMAGE_MOVE_3		"images/Character/Character/MOVE_4.tga"
#define FILEPATH_CHARIMAGE_MOVE_4		"images/Character/Character/MOVE_5.tga"
#define FILEPATH_CHARIMAGE_MOVE_END		"images/Character/Character/MOVE_6.tga"
//--------------------------------------------------------------------

//--------------------------------------------------------------------
// FILEPATH CHARACTER ATTACK
//--------------------------------------------------------------------

// --------------------------	DUALSWORD	--------------------------
#define FILEPATH_CHARIMAGE_PRIMARY_ATTACK_DUALSWORD_START			"images/Character/Weapon/Character/Dualsword/PRIMARY_ATTACK_1.tga"
#define FILEPATH_CHARIMAGE_PRIMARY_ATTACK_DUALSWORD_1				"images/Character/Weapon/Character/Dualsword/PRIMARY_ATTACK_2.tga"
#define FILEPATH_CHARIMAGE_PRIMARY_ATTACK_DUALSWORD_END				"images/Character/Weapon/Character/Dualsword/PRIMARY_ATTACK_3.tga"
//--------------------------------------------------------------------
#define FILEPATH_CHARIMAGE_SECONDARY_ATTACK_DUALSWORD_START			"images/Character/Weapon/Character/Dualsword/SECONDARY_ATTACK_1.tga"
#define FILEPATH_CHARIMAGE_SECONDARY_ATTACK_DUALSWORD_END			"images/Character/Weapon/Character/Dualsword/SECONDARY_ATTACK_2.tga"
//--------------------------------------------------------------------

//--------------------------	LONGSWORD	--------------------------
#define FILEPATH_CHARIMAGE_PRIMARY_ATTACK_LONGSWORD_START			"images/Character/Weapon/Character/Longsword/PRIMARY_ATTACK_1.tga"
#define FILEPATH_CHARIMAGE_PRIMARY_ATTACK_LONGSWORD_1				"images/Character/Weapon/Character/Longsword/PRIMARY_ATTACK_2.tga"
#define FILEPATH_CHARIMAGE_PRIMARY_ATTACK_LONGSWORD_END				"images/Character/Weapon/Character/Longsword/PRIMARY_ATTACK_3.tga"
//--------------------------------------------------------------------
#define FILEPATH_CHARIMAGE_SECONDARY_ATTACK_LONGSWORD_START			"images/Character/Weapon/Character/Longsword/SECONDARY_ATTACK_1.tga"
#define FILEPATH_CHARIMAGE_SECONDARY_ATTACK_LONGSWORD_END			"images/Character/Weapon/Character/Longsword/SECONDARY_ATTACK_2.tga"
//--------------------------------------------------------------------

//--------------------------	SWORD AND SHIELD	--------------------------
#define FILEPATH_CHARIMAGE_PRIMARY_ATTACK_SWORDANDSHIELD_START		"images/Character/Weapon/Character/SwordAndShield/PRIMARY_ATTACK_1.tga"
#define FILEPATH_CHARIMAGE_PRIMARY_ATTACK_SWORDANDSHIELD_1			"images/Character/Weapon/Character/SwordAndShield/PRIMARY_ATTACK_2.tga"
#define FILEPATH_CHARIMAGE_PRIMARY_ATTACK_SWORDANDSHIELD_END		"images/Character/Weapon/Character/SwordAndShield/PRIMARY_ATTACK_3.tga"
//--------------------------------------------------------------------
#define FILEPATH_CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_START	"images/Character/Weapon/Character/SwordAndShield/SECONDARY_ATTACK_1.tga"
#define FILEPATH_CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_1		"images/Character/Weapon/Character/SwordAndShield/SECONDARY_ATTACK_2.tga"
#define FILEPATH_CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_2		"images/Character/Weapon/Character/SwordAndShield/SECONDARY_ATTACK_3.tga"
#define FILEPATH_CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_3		"images/Character/Weapon/Character/SwordAndShield/SECONDARY_ATTACK_4.tga"
#define FILEPATH_CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_4		"images/Character/Weapon/Character/SwordAndShield/SECONDARY_ATTACK_5.tga"
#define FILEPATH_CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_END		"images/Character/Weapon/Character/SwordAndShield/SECONDARY_ATTACK_6.tga"
//--------------------------------------------------------------------

// -----------------------------------------------------
//  Character Class 
// -----------------------------------------------------

class Character
	: public Object
{
public:
	enum CHARACTER_IMAGE
	{
		// CHARACTER NORMAL
		CHARIMAGE_IDLE_START = 0,
		CHARIMAGE_IDLE_END,
		//
		CHARIMAGE_INAIR_START,
		CHARIMAGE_INAIR_END,
		//
		CHARIMAGE_DEATH_START,
		CHARIMAGE_DEATH_END,
		//
		CHARIMAGE_HURT_START,
		CHARIMAGE_HURT_END,
		//
		CHARIMAGE_MOVE_START,
		CHARIMAGE_MOVE_1,
		CHARIMAGE_MOVE_2,
		CHARIMAGE_MOVE_3,
		CHARIMAGE_MOVE_4,
		CHARIMAGE_MOVE_END,

		// ATTACK DUALSWORD
		CHARIMAGE_PRIMARY_ATTACK_DUALSWORD_START,
		CHARIMAGE_PRIMARY_ATTACK_DUALSWORD_1,
		CHARIMAGE_PRIMARY_ATTACK_DUALSWORD_END,
		//
		CHARIMAGE_SECONDARY_ATTACK_DUALSWORD_START,
		CHARIMAGE_SECONDARY_ATTACK_DUALSWORD_END,

		// ATTACK LONGSWORD
		CHARIMAGE_PRIMARY_ATTACK_LONGSWORD_START,
		CHARIMAGE_PRIMARY_ATTACK_LONGSWORD_1,
		CHARIMAGE_PRIMARY_ATTACK_LONGSWORD_END,
		//
		CHARIMAGE_SECONDARY_ATTACK_LONGSWORD_START,
		CHARIMAGE_SECONDARY_ATTACK_LONGSWORD_END,

		// ATTACK SWORDANDSHIELD
		CHARIMAGE_PRIMARY_ATTACK_SWORDANDSHIELD_START,
		CHARIMAGE_PRIMARY_ATTACK_SWORDANDSHIELD_1,
		CHARIMAGE_PRIMARY_ATTACK_SWORDANDSHIELD_END,
		//
		CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_START,
		CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_1,
		CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_2,
		CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_3,
		CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_4,
		CHARIMAGE_SECONDARY_ATTACK_SWORDANDSHIELD_END,
		//
		TOTAL,
	};

private:
	// Image
	//	-- Character
	int				sprite_anim_start,
					sprite_anim_end,
	//	-- Idle
					sprite_idle_strt,
					sprite_idle_end,
	//	-- In Air
					sprite_inair_strt,
					sprite_inair_end,
	//	-- Death
					sprite_death_strt,
					sprite_death_end,
	//	-- Hurt
					sprite_hurt_strt,
					sprite_hurt_end,
	//	-- Move
					sprite_move_strt,
					sprite_move_end,
	//	-- Primary Attack
					sprite_pri_atk_track_strt,
					sprite_pri_atk_track_end,
					sprite_pri_atk_do_atk,
	//	-- Secondary Attack
					sprite_sec_atk_track_strt,
					sprite_sec_atk_track_end,
					sprite_sec_atk_do_atk;

	// Character
	//	-- Collided With Things That Kill Him
	bool			char_hit,
	//	-- Dead
					char_dead,
	//	-- Moving
					char_moving,
	//	-- Deny Move
					char_denymove,
	//	-- Attacking
					char_attacking_pri,
					char_attacking_sec,
					char_attack_allow,
	//	-- Status
					char_status_invul;
	//	-- Jump Tracker
	float			char_jumptracker;

	// Weapon
	//	-- Weapon
	CWeapon*		weapon_weapon;
	Vector3D		weapon_offset_sec;
	bool			weapon_offset_apply,
	//	-- Attack
					weapon_sec_atk_key_hold;
	//	-- Unlock
	bool*			weapon_unlocked;
	int*			weapon_level;
	//	-- Tracker
	bool			weapon_dualsword_tracker_move;

	// Timer
	long			timer_sprite_char;

	CCountdownTimer timer_char_status_invul_after_hit,
					timer_weapon_timeallowed,
					timer_weapon_chargetime;

	// Inventory
	Inventory*		theInventory;

	// Dualsword Secondary Attack Movement
	void Weapon_Sec_Atk_Dualsword(const float elapsed);

	// SwordAndShield Secondary Attack Movement
	void Weapon_Sec_Atk_SwordAndShield(const float elapsed);

public:
	// Constructor
	Character(void);
	// Destructor
	~Character(void);

	// --------------
	// --- OBJECT ---
	// --------------

	// First Initialisation
	bool InitialiseDeclare(const CWeapon::WEAPON weaponchoice, MouseInfo *mouseInfo);

	// Initialise Character
	bool Initialise(const CWeapon::WEAPON weaponchoice = WEAPONDEFAULT, const Vector3D character_position = Vector3D( CHAR_POS_X, CHAR_POS_Y, 0.0f ), const Vector3D hud_position = Vector3D( CHAR_POS_X_HUD, CHAR_POS_Y_HUD, 0.0f ), const Vector3D size = Vector3D( CHAR_SIZE_X, CHAR_SIZE_Y, 0.0f ), const float lives = CHAR_LIVES, const float move_speed = CHAR_SPEED_MOVE);

	// Function that resets the character class
	bool ResetCharacter(const bool dead = false, const float lives = CHAR_LIVES, const float move_speed = CHAR_SPEED_MOVE, const bool invertimage = false);

	// Update Character
	bool UpdateObject(float elapsed);

	// Draw Character
	void RenderObject(void);
	
	// -----------------
	// --- CHARACTER ---
	// -----------------
	
	// Function for character to move left and/or right
	bool		Move_Character_Horizontal			(const bool direction_left, const float elapsed);

	// Function for character to jump
	bool		Move_Character_Jump					(void);

	// Function for character to stop jumping
	void		Move_Character_Jump_End				(void)						{ this->char_jumptracker = 0.0f; }

	// Function for character to do attack ( primary == true / secondary == false )
	bool		Move_Character_Attack				(const bool primary);

	// Function that does the necessary for when the character has been hit by something
	void		ReduceLife							(float life_reduce_by);

	// Function that sets the position of the character
	void		Set_Character_Position				(const Vector3D position)	{ this->hOff = position; }

	// Function that sets the HUD position of the character
	void		Set_Character_Position_HUD			(const Vector3D position)	{ Object::SetPosition( position ); }

	// Function that determines whether the character is moving
	void		Set_Character_Moving				(const bool moving = true)	{ this->char_moving = moving; }

	// Function that determines whether the character is able to move
	void		Set_Character_Move_Deny				(const bool deny = true)	{ this->char_denymove = deny; }

	// Function that determines whether the character is attacking with primary
	void		Set_Character_Attacking_Primary		(const bool attack = true)	{ this->char_attacking_pri = attack; }

	// Function that determines whether the character is attacking with secondary
	void		Set_Character_Attacking_Secondary	(const bool attack = true)	{ this->char_attacking_sec = attack; }

	// Function that determines whether the character is invulnerable to attacks
	void		Set_Character_Status_Invulnerable	(const bool invul = true)	{ this->char_status_invul = invul; }
	
	// Function that determines whether the character is attacking with secondary
	bool		Check_Character_Move_Deny			(void)						{ return this->char_denymove; }

	// Function to check if character is dead
	bool		Check_Character_Dead				(void)						{ return this->char_dead; }

	// Function to check whether character is in the air
	bool		Check_Character_InAir				(void)						{ return !( this->GetOnGround() ); }

	// Function to check whether character is attacking with primary
	bool		Check_Character_Attacking_Primary	(void)						{ return this->char_attacking_pri; }

	// Function to check whether character is attacking with secondary
	bool		Check_Character_Attacking_Secondary	(void)						{ return this->char_attacking_sec; }

	// Fucntion to check whether character is invulnerable
	bool		Check_Character_Status_Invulnerable	(void)						{ return this->char_status_invul; }

	// Function to get character's position
	Vector3D	Get_Character_Position				(void)						{ return this->hOff; }

	// Function to get character's weapon
	CWeapon*	Get_Character_Weapon				(void)						{ return this->weapon_weapon; }

	// -------------
	// --- LIVES ---
	// -------------

	// Function to check if player has any lives left
	bool		Check_Lives_Dead	(void)
	{
		// If no lives left, character is dead
		// Else character is alive
		if ( GetLife() <= 0.0f )	return true;
		else						return false;
	}

	// --------------
	// --- OTHERS ---
	// --------------

	// Function to get inventory
	Inventory*	GetInventory							(void)	{ return this->theInventory; }

	// Release of secondary attack key
	void		Weapon_Sec_Atk_Stop_Hold				(void);

	// Function to level weapon
	bool		Weapon_Level							(const CWeapon::WEAPON weapon, const int amount = 1);
	
	// Function to lock/unlock weapon
	bool		Weapon_Unlock							(const CWeapon::WEAPON weapon, const bool unlock = true);

	// Function to select weapon character uses
	bool		Weapon_Select							(const CWeapon::WEAPON weapon);

	// Function to check level of weapon
	int			Check_Weapon_Level						(const CWeapon::WEAPON weapon)	{ return this->weapon_level[ static_cast<int>( weapon ) ]; } 

	// Function to check unlocked status of weapon
	int			Check_Weapon_Unlock_Status				(const CWeapon::WEAPON weapon)	{ return this->weapon_unlocked[ static_cast<int>( weapon ) ]; } 

	// Save function
	bool		Save									(const char* filename = FILEPATH_SAVELOAD);

	// Load function
	bool		Load									(const char* filename = FILEPATH_SAVELOAD);
};